/**
 * @file    sdk.c
 * @brief
 *
 * DAPLink Interface Firmware
 * Copyright (c) 2017-2017, ARM Limited, All Rights Reserved
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stm32f1xx.h"
#include "stm32f103xb.h"
#include "DAP_config.h"
#include "gpio.h"
#include "daplink.h"
#include "util.h"
#include "cortex_m.h"
#include "stm32f1xx_hal_rcc.h"
#include "stm32f1xx_hal_flash.h"

TIM_HandleTypeDef timer;
uint32_t time_count;
static uint32_t tim2_clk_div(uint32_t apb1clkdiv);

/**
 * @brief  Switch the PLL source from HSI to HSE bypass, and select the PLL as SYSCLK
 *         source.
 *         The system Clock is configured as follow :
 *            System Clock source            = PLL (HSE bypass)
 *            SYSCLK(Hz)                     = 216000000 = 8000000 * 27
 *            HCLK(Hz)                       = 216000000 = 8000000 * 27
 *            AHB Prescaler                  = 1
 *            APB1 Prescaler                 = 2
 *            APB2 Prescaler                 = 1
 *            HSE Frequency(Hz)              = 8000000
 *            HSE PREDIV1                    = 1
 *            PLLMUL                         = 27
 *            Flash Latency(WS)              = 2
 * @param  None
 * @retval None
 */
/*****************************************重新配置时钟************************************************/
// 为Air32F103xx修改，返回固定频率
#define SysFreq_Set (*((void (*)(uint32_t, FlashClkDiv, uint8_t, uint8_t))(*(uint32_t *)0x1FFFD00C)))
#define RCC_SYSCLKSource_PLLCLK ((uint32_t)0x00000002)
#define RCC_PLLSource_HSE_Div1 ((uint32_t)0x00010000)
#define CR_HSEBYP_Reset ((uint32_t)0xFFFBFFFF)
#define CR_HSEON_Reset ((uint32_t)0xFFFEFFFF)
#define CFGR_SW_Mask ((uint32_t)0xFFFFFFFC)
#define CR_HSEON_Set ((uint32_t)0x00010000)
#define FLAG_Mask ((uint8_t)0x1F)
#define RCC_PLLMul_2 ((uint32_t)0x00000000)
#define RCC_PLLMul_3 ((uint32_t)0x00040000)
#define RCC_PLLMul_4 ((uint32_t)0x00080000)
#define RCC_PLLMul_5 ((uint32_t)0x000C0000)
#define RCC_PLLMul_6 ((uint32_t)0x00100000)
#define RCC_PLLMul_7 ((uint32_t)0x00140000)
#define RCC_PLLMul_8 ((uint32_t)0x00180000)
#define RCC_PLLMul_9 ((uint32_t)0x001C0000)
#define RCC_PLLMul_10 ((uint32_t)0x00200000)
#define RCC_PLLMul_11 ((uint32_t)0x00240000)
#define RCC_PLLMul_12 ((uint32_t)0x00280000)
#define RCC_PLLMul_13 ((uint32_t)0x002C0000)
#define RCC_PLLMul_14 ((uint32_t)0x00300000)
#define RCC_PLLMul_15 ((uint32_t)0x00340000)
#define RCC_PLLMul_16 ((uint32_t)0x00380000)
#define RCC_PLLMul_17 ((uint32_t)0x10000000)
#define RCC_PLLMul_18 ((uint32_t)0x10040000)
#define RCC_PLLMul_19 ((uint32_t)0x10080000)
#define RCC_PLLMul_20 ((uint32_t)0x100C0000)
#define RCC_PLLMul_21 ((uint32_t)0x10100000)
#define RCC_PLLMul_22 ((uint32_t)0x10140000)
#define RCC_PLLMul_23 ((uint32_t)0x10180000)
#define RCC_PLLMul_24 ((uint32_t)0x101C0000)
#define RCC_PLLMul_25 ((uint32_t)0x10200000)
#define RCC_PLLMul_26 ((uint32_t)0x10240000)
#define RCC_PLLMul_27 ((uint32_t)0x10280000)
#define RCC_PLLMul_28 ((uint32_t)0x102C0000)
#define RCC_PLLMul_29 ((uint32_t)0x10300000)
#define RCC_PLLMul_30 ((uint32_t)0x10340000)
#define RCC_PLLMul_31 ((uint32_t)0x10380000)
#define RCC_PLLMul_32 ((uint32_t)0x103C0000)
typedef enum
{
  FLASH_Div_0 = 0,
  FLASH_Div_2 = 1,
  FLASH_Div_4 = 2,
  FLASH_Div_6 = 3,
  FLASH_Div_8 = 4,
  FLASH_Div_16 = 5,
} FlashClkDiv;

FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
{
  uint32_t tmp = RCC_FLAG >> 5;
  uint32_t statusreg = RCC->CSR;
  FlagStatus bitstatus = RESET;
  if (tmp == 1)
  {
    statusreg = RCC->CR;
  }
  else if (tmp == 2)
  {
    statusreg = RCC->BDCR;
  }
  tmp = RCC_FLAG & FLAG_Mask;
  return ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET) ? SET : RESET;
}

void RCC_ClkConfiguration(void)
{
  volatile uint32_t sramsize = 0;
  // RCC_DeInit();  复位RCC寄存器
  RCC->CR |= (uint32_t)0x00000001;
  RCC->CFGR &= (uint32_t)0xF8FF0000;
  RCC->CR &= (uint32_t)0xFEF6FFFF;
  RCC->CR &= (uint32_t)0xFFFBFFFF;
  RCC->CFGR &= (uint32_t)0xFF80FFFF;
  RCC->CIR = 0x009F0000;
  // RCC_HSEConfig(RCC_HSE_ON); 使能HSE
  RCC->CR &= CR_HSEON_Reset;
  RCC->CR &= CR_HSEBYP_Reset;
  RCC->CR |= CR_HSEON_Set;
  while (RCC_GetFlagStatus(0x31) == RESET) // 等待HSE就绪
  {
  }
  // RCC_PLLCmd(DISABLE); 关闭PLL
  *(__IO uint32_t *)CR_PLLON_BB = (uint32_t)DISABLE;
  // AIR_RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_27, FLASH_Div_2); 配置PLL,8*27=216MHz
  *(volatile uint32_t *)(0x400210F0) = 1;
  *(volatile uint32_t *)(0x40016C00) = 0xa7d93a86;
  *(volatile uint32_t *)(0x40016C00) = 0xab12dfcd;
  *(volatile uint32_t *)(0x40016C00) = 0xcded3526;
  sramsize = *(volatile uint32_t *)(0x40016C18);
  *(volatile uint32_t *)(0x40016C18) = 0x200183FF; // 配置sram大小, 将BOOT使用对sram打开
  *(volatile uint32_t *)(0x4002228C) = 0xa5a5a5a5;
  SysFreq_Set(RCC_PLLMul_27, FLASH_Div_2, 0, 1);
  RCC->CFGR = (RCC->CFGR & ~0x00030000) | RCC_PLLSource_HSE_Div1;
  *(volatile uint32_t *)(0x40016C18) = sramsize;
  *(volatile uint32_t *)(0x400210F0) = 0;
  *(volatile uint32_t *)(0x40016C00) = ~0xa7d93a86;
  *(volatile uint32_t *)(0x40016C00) = ~0xab12dfcd;
  *(volatile uint32_t *)(0x40016C00) = ~0xcded3526;
  *(volatile uint32_t *)(0x4002228C) = ~0xa5a5a5a5;
  // RCC_PLLCmd(ENABLE); 使能PLL
  *(__IO uint32_t *)CR_PLLON_BB = (uint32_t)ENABLE;
  while (RCC_GetFlagStatus(0x39) == RESET) // 等待PLL就绪
  {
  }
  uint32_t tmpreg = 0;
  tmpreg = RCC->CFGR;
  tmpreg &= CFGR_SW_Mask;
  tmpreg |= RCC_SYSCLKSource_PLLCLK;
  RCC->CFGR = tmpreg;
  // RCC_HCLKConfig(RCC_SYSCLK_Div1); //配置AHB时钟
  tmpreg = RCC->CFGR;
  tmpreg &= ((uint32_t)0xFFFFFF0F);
  tmpreg |= ((uint32_t)0x00000000);
  RCC->CFGR = tmpreg;
  // RCC_PCLK1Config(RCC_HCLK_Div2);	 //配置APB1时钟
  tmpreg = RCC->CFGR;
  tmpreg &= ((uint32_t)0xFFFFF8FF);
  tmpreg |= ((uint32_t)0x00000400);
  RCC->CFGR = tmpreg;
  // RCC_PCLK2Config(RCC_HCLK_Div1);	 //配置APB2时钟
  tmpreg = RCC->CFGR;
  tmpreg &= ((uint32_t)0xFFFFC7FF);
  tmpreg |= ((uint32_t)0x00000000) << 3;
  RCC->CFGR = tmpreg;

  // RCC_LSICmd(ENABLE); //使能内部低速时钟
  *(__IO uint32_t *)CSR_LSION_BB = (uint32_t)1;
  while (RCC_GetFlagStatus(((uint8_t)0x61)) == RESET)
  {
    // 等待LSI就绪
  }
  // RCC_HSICmd(ENABLE); 使能内部高速时钟
  *(__IO uint32_t *)CR_HSION_BB = (uint32_t)1;
  while (RCC_GetFlagStatus(((uint8_t)0x21)) == RESET)
  {
    // 等待HSI就绪
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////

void sdk_init()
{
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};

  SystemCoreClockUpdate();
  HAL_Init();

  /* Select HSI as system clock source to allow modification of the PLL configuration */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
  {
    /* Initialization Error */
    util_assert(0);
  }

  /* Enable HSE bypass Oscillator, select it as PLL source and finally activate the PLL */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_CR_HSEON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    /* Initialization Error */
    util_assert(0);
  }

  /* Select the PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */
  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    /* Initialization Error */
    util_assert(0);
  }
  RCC_ClkConfiguration();
}

HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  HAL_StatusTypeDef ret;
  RCC_ClkInitTypeDef clk_init;
  uint32_t unused;
  uint32_t prescaler;
  uint32_t source_clock;

  HAL_RCC_GetClockConfig(&clk_init, &unused);

  /* Compute the prescaler value to have TIMx counter clock equal to 4000 Hz */
  source_clock = SystemCoreClock / tim2_clk_div(clk_init.APB1CLKDivider);
  prescaler = (uint32_t)(source_clock / 4000) - 1;

  /* Set TIMx instance */
  timer.Instance = TIM2;

  timer.Init.Period = 0xFFFF;
  timer.Init.Prescaler = prescaler;
  timer.Init.ClockDivision = 0;
  timer.Init.CounterMode = TIM_COUNTERMODE_UP;
  timer.Init.RepetitionCounter = 0;

  __HAL_RCC_TIM2_CLK_ENABLE();

  ret = HAL_TIM_Base_DeInit(&timer);
  if (ret != HAL_OK)
  {
    return ret;
  }

  time_count = 0;
  ret = HAL_TIM_Base_Init(&timer);
  if (ret != HAL_OK)
  {
    return ret;
  }

  ret = HAL_TIM_Base_Start(&timer);
  if (ret != HAL_OK)
  {
    return ret;
  }

  return HAL_OK;
}

void HAL_IncTick(void)
{
  // Do nothing
}

uint32_t HAL_GetTick(void)
{
  cortex_int_state_t state;
  state = cortex_int_get_and_disable();
  const uint32_t ticks = __HAL_TIM_GET_COUNTER(&timer) / 4;
  time_count += (ticks - time_count) & 0x3FFF;
  cortex_int_restore(state);
  return time_count;
}

void HAL_SuspendTick(void)
{
  HAL_TIM_Base_Start(&timer);
}

void HAL_ResumeTick(void)
{
  HAL_TIM_Base_Stop(&timer);
}

static uint32_t tim2_clk_div(uint32_t apb1clkdiv)
{
  switch (apb1clkdiv)
  {
  case RCC_CFGR_PPRE1_DIV2:
    return 1;
  case RCC_CFGR_PPRE1_DIV4:
    return 2;
  case RCC_CFGR_PPRE1_DIV8:
    return 4;
  case RCC_CFGR_PPRE1_DIV16:
    return 8;
  default:
    return 1;
  }
}
